using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using AuthService.Application.Security;
using AuthService.Domain.Security;

namespace AuthService.EntityFrameworkCore.Security
{
    /// <summary>
    /// 风险评估仓储实现
    /// </summary>
    public class RiskAssessmentRepository : EfCoreRepository<AuthServiceDbContext, RiskAssessment, Guid>, IRiskAssessmentRepository
    {
        public RiskAssessmentRepository(IDbContextProvider<AuthServiceDbContext> dbContextProvider)
            : base(dbContextProvider)
        {
        }

        public async Task<List<RiskAssessment>> GetByUserIdAsync(Guid userId, CancellationToken cancellationToken = default)
        {
            return await DbSet
                .Where(x => x.UserId == userId)
                .OrderByDescending(x => x.AssessedAt)
                .ToListAsync(GetCancellationToken(cancellationToken));
        }

        public async Task<RiskAssessment> GetLatestByUserIdAsync(Guid userId, string actionType, CancellationToken cancellationToken = default)
        {
            return await DbSet
                .Where(x => x.UserId == userId && x.ActionType == actionType)
                .OrderByDescending(x => x.AssessedAt)
                .FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
        }

        public async Task<List<RiskAssessment>> GetHighRiskAssessmentsAsync(Guid? tenantId = null, CancellationToken cancellationToken = default)
        {
            return await DbSet
                .Where(x => (x.RiskLevel == "High" || x.RiskLevel == "Critical") &&
                           (!tenantId.HasValue || x.TenantId == tenantId))
                .OrderByDescending(x => x.AssessedAt)
                .ToListAsync(GetCancellationToken(cancellationToken));
        }

        public async Task<List<RiskAssessment>> GetByDateRangeAsync(DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default)
        {
            return await DbSet
                .Where(x => x.AssessedAt >= startTime && x.AssessedAt <= endTime)
                .OrderByDescending(x => x.AssessedAt)
                .ToListAsync(GetCancellationToken(cancellationToken));
        }

        public async Task<List<RiskAssessment>> GetByUserIdAndActionTypeAsync(Guid userId, string actionType, int maxCount = 10, CancellationToken cancellationToken = default)
        {
            return await DbSet
                .Where(x => x.UserId == userId && x.ActionType == actionType)
                .OrderByDescending(x => x.AssessedAt)
                .Take(maxCount)
                .ToListAsync(GetCancellationToken(cancellationToken));
        }

        public async Task<List<RiskAssessment>> GetListAsync(string filter = null, string riskLevel = null, int maxResultCount = 10, int skipCount = 0, CancellationToken cancellationToken = default)
        {
            var query = DbSet.AsQueryable();

            if (!string.IsNullOrEmpty(filter))
            {
                query = query.Where(x =>
                    x.AssessmentId.Contains(filter) ||
                    x.ActionType.Contains(filter) ||
                    x.RejectionReason.Contains(filter));
            }

            if (!string.IsNullOrEmpty(riskLevel))
            {
                query = query.Where(x => x.RiskLevel == riskLevel);
            }

            return await query
                .OrderByDescending(x => x.AssessedAt)
                .Skip(skipCount)
                .Take(maxResultCount)
                .ToListAsync(GetCancellationToken(cancellationToken));
        }

        public async Task<long> GetCountAsync(string filter = null, string riskLevel = null, CancellationToken cancellationToken = default)
        {
            var query = DbSet.AsQueryable();

            if (!string.IsNullOrEmpty(filter))
            {
                query = query.Where(x =>
                    x.AssessmentId.Contains(filter) ||
                    x.ActionType.Contains(filter) ||
                    x.RejectionReason.Contains(filter));
            }

            if (!string.IsNullOrEmpty(riskLevel))
            {
                query = query.Where(x => x.RiskLevel == riskLevel);
            }

            return await query.CountAsync(cancellationToken);
        }

        public async Task<int> CleanupExpiredAssessmentsAsync(CancellationToken cancellationToken = default)
        {
            var expireDate = DateTime.Now.AddDays(-30); // 默认30天前
            var expiredAssessments = await DbSet
                .Where(x => x.AssessedAt < expireDate)
                .ToListAsync(GetCancellationToken(cancellationToken));

            if (expiredAssessments.Any())
            {
                await DeleteManyAsync(expiredAssessments, autoSave: true, cancellationToken: cancellationToken);
            }

            return expiredAssessments.Count;
        }

        public async Task<int> DeleteExpiredAssessmentsAsync(DateTime expireDate, CancellationToken cancellationToken = default)
        {
            var expiredAssessments = await DbSet
                .Where(x => x.AssessedAt < expireDate)
                .ToListAsync(GetCancellationToken(cancellationToken));

            if (expiredAssessments.Any())
            {
                await DeleteManyAsync(expiredAssessments, autoSave: true, cancellationToken: cancellationToken);
            }

            return expiredAssessments.Count;
        }

        public async Task<RiskAssessment> GetByAssessmentIdAsync(string assessmentId, CancellationToken cancellationToken = default)
        {
            return await DbSet
                .FirstOrDefaultAsync(x => x.AssessmentId == assessmentId, GetCancellationToken(cancellationToken));
        }

        public async Task<List<RiskAssessment>> GetByIpAddressAsync(string ipAddress, CancellationToken cancellationToken = default)
        {
            return await DbSet
                .Where(x => x.IpAddress == ipAddress)
                .OrderByDescending(x => x.AssessedAt)
                .ToListAsync(GetCancellationToken(cancellationToken));
        }

        public async Task<List<RiskAssessment>> GetRejectedAssessmentsAsync(CancellationToken cancellationToken = default)
        {
            return await DbSet
                .Where(x => !x.IsAllowed)
                .OrderByDescending(x => x.AssessedAt)
                .ToListAsync(GetCancellationToken(cancellationToken));
        }

        public async Task<List<RiskAssessment>> GetUnprocessedAssessmentsAsync(CancellationToken cancellationToken = default)
        {
            return await DbSet
                .Where(x => !x.IsProcessed)
                .OrderByDescending(x => x.AssessedAt)
                .ToListAsync(GetCancellationToken(cancellationToken));
        }

        public async Task<List<RiskAssessment>> GetExpiredAssessmentsAsync(CancellationToken cancellationToken = default)
        {
            return await DbSet
                .Where(x => x.ExpiresAt < DateTime.Now)
                .OrderByDescending(x => x.AssessedAt)
                .ToListAsync(GetCancellationToken(cancellationToken));
        }

        public async Task MarkAssessmentsAsProcessedAsync(List<Guid> assessmentIds, string processedBy = null, CancellationToken cancellationToken = default)
        {
            var assessments = await DbSet
                .Where(x => assessmentIds.Contains(x.Id))
                .ToListAsync(GetCancellationToken(cancellationToken));

            foreach (var assessment in assessments)
            {
                assessment.IsProcessed = true;
                assessment.ProcessedTime = DateTime.Now;
                assessment.ProcessedBy = processedBy;
            }

            await SaveChangesAsync(cancellationToken);
        }

        public async Task<RiskAssessmentStatisticsDto> GetAssessmentStatisticsAsync(DateTime? startTime = null, DateTime? endTime = null, Guid? userId = null, string actionType = null, CancellationToken cancellationToken = default)
        {
            var query = DbSet.AsQueryable();

            if (startTime.HasValue)
            {
                query = query.Where(x => x.AssessedAt >= startTime.Value);
            }

            if (endTime.HasValue)
            {
                query = query.Where(x => x.AssessedAt <= endTime.Value);
            }

            if (userId.HasValue)
            {
                query = query.Where(x => x.UserId == userId.Value);
            }

            if (!string.IsNullOrEmpty(actionType))
            {
                query = query.Where(x => x.ActionType == actionType);
            }

            var assessments = await query.ToListAsync(cancellationToken);

            return new RiskAssessmentStatisticsDto
            {
                TotalAssessments = assessments.Count,
                AllowedAssessments = assessments.Count(x => x.IsAllowed),
                RejectedAssessments = assessments.Count(x => !x.IsAllowed),
                HighRiskAssessments = assessments.Count(x => x.RiskLevel == "High" || x.RiskLevel == "Critical"),
                UnprocessedAssessments = assessments.Count(x => !x.IsProcessed),
                AverageRiskScore = assessments.Any() ? assessments.Average(x => x.RiskScore) : 0f,
                AssessmentsByActionType = assessments.GroupBy(x => x.ActionType).ToDictionary(g => g.Key, g => g.Count()),
                AssessmentsByRiskLevel = assessments.GroupBy(x => x.RiskLevel).ToDictionary(g => g.Key, g => g.Count()),
                AssessmentsByDate = assessments.GroupBy(x => x.AssessedAt.Date).ToDictionary(g => g.Key, g => g.Count())
            };
        }

        // 添加缺失的重载方法以满足接口要求
        public async Task<List<RiskAssessment>> GetByUserIdAndActionTypeAsync(Guid userId, string actionType, CancellationToken cancellationToken = default)
        {
            return await GetByUserIdAndActionTypeAsync(userId, actionType, 10, cancellationToken);
        }

        public new async Task<List<RiskAssessment>> GetHighRiskAssessmentsAsync(CancellationToken cancellationToken = default)
        {
            return await GetHighRiskAssessmentsAsync(null, cancellationToken);
        }
    }
}